home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XS.ZIP / LIB / IMPORT.C < prev    next >
C/C++ Source or Header  |  1992-11-27  |  26KB  |  582 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    i m p o r t . c                                                 */
  3. /*                                                                    */
  4. /*    File name mapping routines for UUPC/extended                    */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1992 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*
  18.  *    $Id: IMPORT.C 1.2 1992/11/22 21:06:14 ahd Exp $
  19.  *
  20.  *    $Log: IMPORT.C $
  21.  * Revision 1.2  1992/11/22  21:06:14  ahd
  22.  * Correct mapping of dos paths with trailing slashes
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <time.h>
  31.  
  32. #include "lib.h"
  33. #include "import.h"
  34. #include "arbmath.h"
  35. #include "hostable.h"
  36. #include "usertabl.h"
  37. #include "security.h"
  38.  
  39. #define MAX_DIGITS 20         /* Number of digits for arb math */
  40.  
  41. /*--------------------------------------------------------------------*/
  42. /*                    Internal function prototypes                    */
  43. /*--------------------------------------------------------------------*/
  44.  
  45. #define min(x,y) (((x) < (y)) ? (x) : (y))
  46.  
  47. currentfile();
  48.  
  49. /*--------------------------------------------------------------------*/
  50. /*                     Local function prototypes                      */
  51. /*--------------------------------------------------------------------*/
  52.  
  53. static void ImportName( char *local, const char *canon, size_t charsetsize );
  54.  
  55. /*-------------------------------------------------------------------*/
  56. /*                                                                   */
  57. /*   i m p o r t p a t h                                             */
  58. /*                                                                   */
  59. /*   Convert a canonical name to a format the host can handle        */
  60. /*                                                                   */
  61. /*   These routines convert file name between canonical form, which  */
  62. /*   is defined as a 'unix' style pathname, and the MS-DOS all       */
  63. /*   uppercase "xxxxxxxx.xxx" format.                                */
  64. /*                                                                   */
  65. /*   If the canonical name does not have a path, that is the file is */
  66. /*   destined for the local spool directory, we can assume the UNIX  */
  67. /*   name will normally be in a format like this:                    */
  68. /*                                                                   */
  69. /*                                                                   */
  70. /*       X.hostid#######            (Execute files)                  */
  71. /*       C.hostid#######            (Call files)                     */
  72. /*       D.hostid#######            (Data files)                     */
  73. /*                                                                   */
  74. /*   where "hostid" may be most, but not always all, of the local    */
  75. /*   host or remote host (the file came from or is going to) and     */
  76. /*   "######" can be any character valid for the UNIX file system.   */
  77. /*   Note, however, that the routine has to be generic to allow for  */
  78. /*   other file names to be placed in the spool directory without    */
  79. /*   collisions.                                                     */
  80. /*                                                                   */
  81. /*   Avoiding collisions in the spool directory is important; when   */
  82. /*   receiving files with mixed case names longer than 11            */
  83. /*   characters, sooner or later a file name collision will occur.   */
  84. /*                                                                   */
  85. /*   We can also assume that only UUPC will see these names, which   */
  86. /*   means we can transform the name using any method we choose, so  */
  87. /*   long as the UUPC functions opening the file always call         */
  88. /*   importpath, and that importpath is reducible (that is, two      */
  89. /*   calls to importpath with the same argument always yield the     */
  90. /*   same result).  Note that if end user really wanted the file in  */
  91. /*   the spool directory, all he has to do is rename the file-- far  */
  92. /*   better than losing the data because duplicate file names.       */
  93. /*                                                                   */
  94. /*   For these files, we map the name as follows:                    */
  95. /*                                                                   */
  96. /*   0 - If the name is a valid MS-DOS name, use it without changing */
  97. /*                                                                   */
  98. /*   1 - Begin the output name by inserting up to the first eight    */
  99. /*       characters of the remote host name (followed by a slash) as */
  100. /*       a subdirectory name.                                        */
  101. /*                                                                   */
  102. /*   2 - If the input name begins with an uppercase alphabetic       */
  103. /*       character followed by a period, also insert the alphabetic  */
  104. /*       (followed by a slash) to make this a second subdirectory.   */
  105. /*       Then, move the logical start of the input name past the two */
  106. /*       characters.                                                 */
  107. /*                                                                   */
  108. /*   3 - Determine the number of characters the local host and       */
  109. /*       remote hosts have equal to the next characters of the input */
  110. /*       name, up to a maximum of 8, and zero the lower of the two   */
  111. /*       counts.  Then, step past the number of characters of the    */
  112. /*       larger count.                                               */
  113. /*                                                                   */
  114. /*       For example, if the file name is X.keane22222 and the local */
  115. /*       host name is kendra (2 characters match) and the remote     */
  116. /*       host is keane1 (5 characters match), zero the number of     */
  117. /*       characters matched by kendra, and make the new start of the */
  118. /*       file name five characters further (at the first "2").       */
  119. /*                                                                   */
  120. /*   4 - Convert the remaining string using a base conversion, with  */
  121. /*       the input character size being from ascii "#" to ascii "z"  */
  122. /*       (88 characters) to the allowed set of characters in MS-DOS  */
  123. /*       file names (charset, below, 52 characters).                 */
  124. /*                                                                   */
  125. /*   5 - Prepend to the string to be converted the length of the     */
  126. /*       remote host added to the length of the local host           */
  127. /*       multiplied by 8 (both lengths were computed in step 3,      */
  128. /*       above).  The base conversion is also applied to this        */
  129. /*       "character", we which know will be in the range 1-64.       */
  130. /*                                                                   */
  131. /*   6 - If the string created by steps 4 and 5 exceeds 8            */
  132. /*       characters, insert a period after the eighth character to   */
  133. /*       make it a valid MS-DOS file name.  If the string created by */
  134. /*       steps 4 and 5 exceeds 11 characters, truncate the string by */
  135. /*       using the first eight and last three characters.            */
  136. /*                                                                   */
  137. /*   7 - Append the string created in steps 4 through 6 to the path  */
  138. /*       name created in steps 1 and 2.                              */
  139. /*                                                                   */
  140. /*   If the canonical name has a path, it is destined for an end     */
  141. /*   user, so we should not radically transform it like we do for    */
  142. /*   files in the spool directory.  Thus, if the canonical name has  */
  143. /*   a path, mung the canonical file name as follows:                */
  144. /*                                                                   */
  145. /*   1 - skip any path from the canonical name                       */
  146. /*                                                                   */
  147. /*   2 - copy up to 8 character from the canonical name converting . */
  148. /*       to _ and uppercase to lowercase.                            */
  149. /*                                                                   */
  150. /*   3 - if the name was longer than 8 character copy a . to the     */
  151. /*       host name and then copy the up to three characters from     */
  152. /*       the tail of the canonical name to the host name.            */
  153. /*                                                                   */
  154. /*   Note that this set of rules will cause a collision with names   */
  155. /*   that only differ in case, but leaves the name in a recongizable */
  156. /*   format for the user.                                            */
  157. /*-------------------------------------------------------------------*/
  158.  
  159.  
  160. void importpath(char *local, char const *canon, char const *remote)
  161. {
  162.    char *s, *out;
  163.    size_t charsetsize;     /* Number of allowed characters in
  164.                               MS-DOS file names                   */
  165.  
  166.    out = local;
  167.  
  168. /*--------------------------------------------------------------------*/
  169. /*                       Verify our parameters                        */
  170. /*--------------------------------------------------------------------*/
  171.  
  172.    if ( local == NULL )
  173.       panic();
  174.    if ( canon == NULL )
  175.       panic();
  176.  
  177. /*--------------------------------------------------------------------*/
  178. /*                      Define our character set                      */
  179. /*--------------------------------------------------------------------*/
  180.  
  181.     if ( E_charset == NULL )
  182.       E_charset = DOSCHARS;
  183.     charsetsize = strlen( E_charset );
  184.  
  185. /*--------------------------------------------------------------------*/
  186. /*                 Determine if spool file directory                  */
  187. /*--------------------------------------------------------------------*/
  188.  
  189.    if ((s = strrchr(canon, '/')) == (char *)NULL)
  190.    {                          /* File for spooling directory, use
  191.                                  internal character set to avoid
  192.                                  collisons                           */
  193.       static size_t range =  UNIX_END_C - UNIX_START_C + 1;
  194.                               /* Determine unique number characters in
  195.                                  the UNIX file names we are mapping  */
  196.  
  197.       size_t remlen = min(HOSTLEN, strlen(remote));
  198.                               /* Length of the remote name passed
  199.                                  in, shortened below to number of
  200.                                  characters matched in name          */
  201.       size_t nodelen = min(HOSTLEN, strlen(E_nodename));
  202.                               /* Length of the local host name,
  203.                                  shortened below to number of
  204.                                  characters matched in name          */
  205.       size_t subscript = 0;   /* Value of UNIX character to be
  206.                                  converted to MS-DOS character set   */
  207.       char *next        = local + remlen;
  208.       char tempname[FILENAME_MAX];
  209.       unsigned char number[MAX_DIGITS];
  210.                               /* Arbitary length number, for base
  211.                                  conversions                        */
  212.  
  213. /*--------------------------------------------------------------------*/
  214. /*                    Verify we have a remote name                    */
  215. /*--------------------------------------------------------------------*/
  216.  
  217.    if ( remote == NULL )
  218.       panic();
  219.  
  220. /*--------------------------------------------------------------------*/
  221. /*    Put the host name (up to six characters) at the beginning of    */
  222. /*    the MS-DOS file name as a sub-directory name.                   */
  223. /*--------------------------------------------------------------------*/
  224.  
  225.       strncpy(local, remote, remlen);
  226.       *next++ = '/';          /* Add in the sub-directory seperator  */
  227.       s = (char *) canon;     /* Get the beginnging of the UNIX name */
  228.  
  229. /*--------------------------------------------------------------------*/
  230. /*    Files in the spooling directory generally start with "D.",      */
  231. /*    "C.", or "X."; strip off any upper case letter followed by a    */
  232. /*    period into its own directory.                                  */
  233. /*--------------------------------------------------------------------*/
  234.  
  235.       if ((s[0] >= 'A') && (s[0] <= 'Z') && (s[1] == '.'))
  236.       {
  237.          *next++ = *s;        /* Copy the input character            */
  238.          *next++ = '/';       /* Add the sub-directory indicator too */
  239.          s += 2;              /* Step input string past the copied
  240.                                  data                                */
  241.       }
  242.  
  243.       while( remlen > 0 )
  244.       {
  245.          if (equaln(remote,s,remlen))
  246.             break;
  247.          remlen--;
  248.       }
  249.  
  250.       while( nodelen > 0 )
  251.       {
  252.          if (equaln(E_nodename,s,nodelen))
  253.             break;
  254.          nodelen--;
  255.       }
  256.  
  257.       if (nodelen > remlen )
  258.       {
  259.          remlen = 0;
  260.          s += nodelen;
  261.       }
  262.       else {
  263.          nodelen = 0;
  264.          s += remlen;
  265.       }
  266.  
  267.       *next  = '\0';          /* Terminate first part of host string */
  268.  
  269. /*--------------------------------------------------------------------*/
  270. /*       Create a binary number which represents our file name        */
  271. /*--------------------------------------------------------------------*/
  272.  
  273.       for (subscript = 0; subscript < MAX_DIGITS; subscript++ )
  274.          number[subscript] = 0;  /* Initialize number to zero        */
  275.  
  276.       add(number, nodelen + remlen * HOSTLEN, MAX_DIGITS);
  277.                                  /* Append host name info to the
  278.                                     front of the converted string    */
  279.  
  280.       while( (*s != '\0') && (*number == '\0'))
  281.       {
  282.          mult(number, range, MAX_DIGITS); /* Shift the number over   */
  283.          add(number, *s++  - UNIX_START_C , MAX_DIGITS);
  284.                                           /* Add in new low order    */
  285.       } /* while */
  286.  
  287. /*-------------------------------------------------------------------*/
  288. /*   We now have stripped off the leading x. and host name, if any;  */
  289. /*   now, convert the remaining characters in the name by doing a    */
  290. /*   range to charset base conversion.                               */
  291. /*-------------------------------------------------------------------*/
  292.  
  293.       out = &tempname[FILENAME_MAX];
  294.       *--out = '\0';          /* Terminate the string we will build  */
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*         Here's the loop to actually do the base conversion         */
  298. /*--------------------------------------------------------------------*/
  299.  
  300.       while(adiv( number, charsetsize, &subscript, MAX_DIGITS))
  301.             *--out = E_charset[ subscript ];
  302.  
  303. /*--------------------------------------------------------------------*/
  304. /*    The conversion is done; now squeeze it into an 11 character     */
  305. /*    MS-DOS name with period.                                        */
  306. /*--------------------------------------------------------------------*/
  307.  
  308.       ImportName( next, out, charsetsize);
  309.  
  310.    }
  311.    else {         /* Not file for spooling directory, convert it  */
  312.  
  313.       char *in = (char *) canon;
  314.  
  315. /*--------------------------------------------------------------------*/
  316. /*      Handle leading drive letter (ignore it, assuming valid)       */
  317. /*--------------------------------------------------------------------*/
  318.  
  319.       if ( isalpha( *in ) && (in[1] == ':'))
  320.       {
  321.          *out++ = *in++;      /* The drive letter                    */
  322.          *out++ = *in++;      /* The colon making it a driver letter */
  323.       } /* if */
  324.  
  325.       if ( *in == '/' )       /* Absolute path name?                 */
  326.          *out++ = *in++;      /* Yes, step past it                   */
  327.  
  328.       while( *in == '/')      /* Additional slashes?                 */
  329.          in++;                /* Skip them,  they mean nothing       */
  330.  
  331.       s = strchr( in, '/' );  /* Get end of next path segment        */
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*              Now convert each simple name in the path              */
  335. /*--------------------------------------------------------------------*/
  336.  
  337.       while ( *in )
  338.       {
  339.          if ( s != NULL )
  340.             *s = '\0';        /* Truncate input string to simple name */
  341.  
  342.          ImportName( out, in , charsetsize );
  343.  
  344.          if ( s == NULL )
  345.             break;
  346.          out = out + strlen( out );
  347.          *out++ = *s++ = '/'; /* Restore path to input and output    */
  348.          in = s;              /* Remember start of this simple name  */
  349.          while( *in == '/')   /* Additional slashes?                 */
  350.             in++;             /* Skip them,  they mean nothing       */
  351.          s = strchr( in , '/' );
  352.       }
  353.  
  354.    } /* else */
  355.  
  356.    printmsg( 3, "ImportPath: Mapped %s to %s", canon, local );
  357.  
  358. } /*importpath*/
  359.  
  360. /*--------------------------------------------------------------------*/
  361. /*    I m p o r t N a m e                                             */
  362. /*                                                                    */
  363. /*    Translate a simple DOS name without the path                    */
  364. /*--------------------------------------------------------------------*/
  365.  
  366. static void ImportName( char *local, const char *canon, size_t charsetsize )
  367. {
  368.  
  369.    char *in = (char *) canon;
  370.    char *out = local;
  371.    size_t len = strlen( canon );
  372.    size_t column;
  373.    char *best_period = NULL;     /* Assume no prince charming         */
  374.  
  375.    if ( strchr(canon,'/') != NULL )
  376.    {
  377.       printmsg(0,"ImportName: Parameter error, not simple name: %s",
  378.             canon);
  379.       panic();
  380.    }
  381.  
  382.    if ( len == 0 )
  383.    {
  384.       printmsg(0,"ImportName: Parameter error, zero length input");
  385.       panic();
  386.    }
  387.  
  388. /*--------------------------------------------------------------------*/
  389. /*                 If a valid DOS name, use it as-is                  */
  390. /*--------------------------------------------------------------------*/
  391.  
  392.    if (ValidDOSName( canon ))
  393.    {
  394.       strcpy( local, canon );
  395.       return;
  396.    }
  397.  
  398. /*--------------------------------------------------------------------*/
  399. /*    If the dataset name has a period, use it.  The rule we          */
  400. /*    follow is use the last period in the second through ninth       */
  401. /*    characters, otherwise use the last period in the dataset        */
  402. /*    name with the exception of leading period.                      */
  403. /*                                                                    */
  404. /*    In any case, we only copy up to eight characters for the        */
  405. /*    dataset name and up to three characters for the extension.      */
  406. /*--------------------------------------------------------------------*/
  407.  
  408.    for ( column = 1; (column < 9) && (in[column] != '\0') ; column++)
  409.    {
  410.       if ( in[column] == '.')
  411.       {
  412.          strncpy( out, in, column + 5 );
  413.                                     /* Period, 3 char extension,
  414.                                        and terminating \0            */
  415.          best_period = &out[column];/* Remember output location of
  416.                                        period in name                */
  417.  
  418.          if ( len > (column + 4) )  /* Need to trunc extension to 3? */
  419.             strcpy( out + column + 1, in + len - 3 ); /* Yes         */
  420.  
  421.          break;
  422.       } /*if */
  423.    }  /* if */
  424.  
  425. /*--------------------------------------------------------------------*/
  426. /*    No period in the first eight characters, search the rest of     */
  427. /*    the name for the last period (unless period is very last        */
  428. /*    character in the string).                                       */
  429. /*--------------------------------------------------------------------*/
  430.  
  431.    if ( best_period == NULL )
  432.    {
  433.  
  434.       strncpy( out , in , 8);
  435.       best_period = strrchr( in+1 , '.');
  436.  
  437.       if ( (best_period != NULL) && (best_period[1] != '\0') )
  438.       {
  439.          strncpy( &out[8], best_period, 4 ); /* Plus period and 3
  440.                                                 in extension         */
  441.  
  442.          if ( strlen( best_period) > 4 )     /* Long Extension?      */
  443.             out[12] = '\0';                  /* Yes --> Truncate     */
  444.  
  445.       } /* if */
  446.       else {                  /* No periods at all, generate one
  447.                                  if needed for long name          */
  448.  
  449.          if ( len > 8 )
  450.          {
  451.             out[8] = '.';
  452.             strcpy(&out[9], in + max(8,(len - 3))  );
  453.          } /* if ( len > 9 ) */
  454.  
  455.       } /* else */
  456.  
  457.       best_period = &out[8];              /* Remember location of
  458.                                              period, okay if past
  459.                                              end of string           */
  460.  
  461.    } /* if ( best_period == NULL ) */
  462.  
  463. /*--------------------------------------------------------------------*/
  464. /*                Now, clean up any invalid characters                */
  465. /*--------------------------------------------------------------------*/
  466.  
  467.    if ( out[ strlen( out ) - 1 ] == '.' ) /* Trailing period?        */
  468.       out[ strlen( out ) - 1 ] = '\0';    /* Just truncate string    */
  469.  
  470.    while( *out != '\0')
  471.    {
  472.       int c ;
  473.       if ( isupper( *out ))
  474.          c = tolower( *out );
  475.       else
  476.          c = *out;
  477.  
  478.       if ((out != best_period) && (strchr( E_charset, c ) == NULL ))
  479.       {
  480.          if ( c > 'z' )
  481.             c -= 62;
  482.          else if ( c > 'Z' )
  483.             c -= 36;
  484.          else if ( c > '9' )
  485.             c -= 10;
  486.          *out = E_charset[ (c - UNIX_START_C) % charsetsize ];
  487.       }
  488.  
  489.       out++;                    /* Step to next character         */
  490.    } /* while( *out != '\0') */
  491.  
  492. /*--------------------------------------------------------------------*/
  493. /*                   Report our results and return                    */
  494. /*--------------------------------------------------------------------*/
  495.  
  496.    printmsg( 5,
  497.             "ImportName: Mapped %s to %s", canon, local );
  498.  
  499. } /* ImportName */
  500.  
  501. /*--------------------------------------------------------------------*/
  502. /*    V a l i d D O S N a m e                                         */
  503. /*                                                                    */
  504. /*    Validate an MS-DOS file name                                    */
  505. /*--------------------------------------------------------------------*/
  506.  
  507. boolean ValidDOSName( const char *s)
  508. {
  509.    char *ptr;
  510.    size_t len = strlen ( s );
  511.    char tempname[FILENAME_MAX];
  512.  
  513. /*--------------------------------------------------------------------*/
  514. /*                      Define our character set                      */
  515. /*--------------------------------------------------------------------*/
  516.  
  517.     if ( E_charset == NULL )
  518.       E_charset = DOSCHARS;
  519.  
  520. /*--------------------------------------------------------------------*/
  521. /*                 Name must be 12 characters or less                 */
  522. /*--------------------------------------------------------------------*/
  523.  
  524.    if (len > 12)
  525.       return FALSE;
  526.  
  527.    strcpy( tempname, s);      /* Make a temp copy we can alter       */
  528.  
  529. /*--------------------------------------------------------------------*/
  530. /*    Simple file name without extension must be eight chracters      */
  531. /*    or less                                                         */
  532. /*--------------------------------------------------------------------*/
  533.  
  534.    ptr = strrchr(tempname, '.');
  535.    if (ptr == NULL)
  536.    {
  537.       if (len > 8)
  538.          return FALSE;
  539.    }
  540.  
  541. /*--------------------------------------------------------------------*/
  542. /*          Period must be in second through ninth character          */
  543. /*--------------------------------------------------------------------*/
  544.  
  545.    else {
  546.       if ((ptr == tempname) || (ptr > &tempname[8]))
  547.          return FALSE;
  548.  
  549. /*--------------------------------------------------------------------*/
  550. /*             Extension must be three characters or less             */
  551. /*--------------------------------------------------------------------*/
  552.  
  553.       if ( strlen( ptr ) > 4) /* Three characters plus the period?   */
  554.          return FALSE;        /* No --> Too much                     */
  555.  
  556. /*--------------------------------------------------------------------*/
  557. /*                          Only one period                           */
  558. /*--------------------------------------------------------------------*/
  559.  
  560.       if (ptr != strchr(tempname, '.'))
  561.          return FALSE;
  562.    } /* else */
  563.  
  564. /*--------------------------------------------------------------------*/
  565. /*                Must only be valid MS-DOS characters                */
  566. /*--------------------------------------------------------------------*/
  567.  
  568.    strlwr( tempname );        /* Map into our desired character set  */
  569.    if ( ptr != NULL )
  570.       *ptr = 'x';             /* We've already accounted for the
  571.                                  period, don't let it ruin our day   */
  572.  
  573.    if (strspn(tempname, E_charset ) == len)
  574.    {
  575.       printmsg(9,"ValidDOSName: \"%s\" is valid", s);
  576.       return TRUE;
  577.    }
  578.    else
  579.       return FALSE;
  580.  
  581. } /* ValidateDOSName */
  582.